Building on the static analysis of Phan, I’ve also recently started using Psalm, a PHP static analyzer from Vimeo’s engineering team. What I particularly love about Psalm is its realtime analysis and integration within PhpStorm. Instead of needing to run a report after any changes, Psalm can highlight issues as they happen with my source code open.
While Psalm includes the necessary language server to integrate with PhpStorm, a plugin is needed to make the connection. I’m using the LSP Support plugin by Guillaume Tâche. Here’s what I did to get everything setup, and some lessons I learned along the way.
Getting Set Up
First, Install Psalm via composer:
composer require --dev vimeo/psalm
Then setup a psalm.xml configuration file. Psalm provides 8 levels of strictness, 1 being the most strict and 3 being the default. I’m using level 4.
./vendor/bin/psalm --init [source_directory=src] [config_level=3]
Next, I have a few of my own helper functions, so I added stubs to those functions inside the psalm.xml. I also use New Relic, and JetBrains helpfully provides a repo that contains pre-defined stubs for numerous libraries.
<stubs> <file name="../phpstorm-stubs/newrelic/newrelic.php"/> <file name="../phpstorm-stubs/funnel-cake/funnel-cake.php"/> </stubs>
At this point Psalm is installed and configured – now let’s get some static analysis goodness from it!
Using Psalm
To see Psalm’s analysis in your console, you’ll only need to run psalm
from the same directory as your psalm.xml
. For some reason for me, I was getting corrupt caches (I think from running psalm while the language server is setup, which i’ll explain below), so I run from the command line with:
psalm --no-progress --no-cache
I’ve setup an External Tool in PhpStorm to run the above, which will show its output from inside of PhpStorm. I’ve actually setup a short script to better format Psalm’s output. PhpStorm needs absolute file paths, and can then link directly to the issue. Save the following script as run_psalm.sh
in the root directory of your project:
psalm --no-progress --no-cache > psalm.out cat psalm.out | sed G | sed -E 's|(.*) - ([a-zA-Z0-9 _\./\-]+:[[:digit:]]+)|'"$(pwd)"'/\2\ \1|g' | perl -pi -0 -w -e 's/\n\n/\n/g' rm psalm.out
Then, in PhpStorm, open up External Tools in the Preferences window:
Then, add a new external tool and fill in the details to run the above script:
I’ve also setup an External Tool for Phan, as I’ve described before, so my Tools → External Tools menu shows both Phan and Psalm options now:
But this is only the first integration – the next one is what’s got me most excited about Psalm – full IDE integration for realtime highlighting of issues.
Language Server Plugin
To get realtime analysis, open up PhpStorm’s plugin marketplace and search for “LSP Support” and you’ll find the plugin by gtache.
After installing the plugin and restarting PhpStorm, you’ll see a new menu in the Languages & Frameworks section of preference window. Open the Server Definitions section.
Set the first drop down it Executable
, and set the Extension
to php
. For the path
, set it to the path of your php
executable. I’m running MAMP, I’ve set my path
to /Applications/MAMP/bin/php/php7.3.8/bin/php
. Last, set the args
to vendor/bin/psalm-language-server
.
Your configuration should look something like this when you’re done:
Restart PhpStorm, open a php file, and if everything goes well you should see the language server icon show the start up success and see the green status icon in the footer.
Now you should be seeing live Psalm feedback inside of PhpStorm!
It’s Not Perfect
There’s a few odd things I’ve noticed when using the language server, here’s a few:
- It doesn’t seem to start until I’ve edited a file. After opening a file, nothing will highlight until i’ve typed at least 1 character into the editor, but then everything will pop in.
- Sometimes it’s slow. I think it re-analyzes after every keystroke, and I wish the LSP Plugin would be a bit gentler here
- I’ve received occasional crashes of the LSP Support plugin. It’s rare enough that it’s not a huge problem, but is a bit of an inconvenience.
- The plugin overwrites the Quick Documentation mouse click with its own popover. I’ve set option+click to open the Quick Documentation window, but instead it was opening the LSP information.
Customizing the LSP Plugin
Because of the crashes I ran into, and the fact that I really liked the older Quick Documentation more than the LSP documentation, I decided to try and customize the plugin just a bit to see if I could change that.
You can find the full source of the LSP Plugin on GitHub: https://github.com/gtache/intellij-lsp. And I’ve forked the code to remove the Quick Documentation override: https://github.com/adamwulf/intellij-lsp/tree/feature/remove-quickdoc. I’ve also fixed some of the crashes I’ve run into, but not all of them.
To build from my fork:
git clone git@github.com:adamwulf/intellij-lsp.git git checkout feature/remove-quickdoc ./gradlew buildPlugin
That will generate a build/distributions/LSP Support.zip
file that you can install into PhpStorm. To install, open the Plugins section, click the gear, and choose Install From Disk, select the .zip file, and away you go.
Conclusion
After learning more about Psalm and its PhpStorm intonations, I now have:
- Realtime analysis for any option files using the LSP Support plugin
- Full project analysis using the External Tools menu option
- A custom LSP plugin for ultimate nerd customization
Links
- Psalm static analyzer: https://psalm.dev
- PhpStorm: https://www.jetbrains.com/phpstorm/
- LSP Support PhpStorm plugin: https://github.com/gtache/intellij-lsp
- My fork of the plugin: https://github.com/adamwulf/intellij-lsp
- Pre-defined code stubs: https://github.com/JetBrains/phpstorm-stubs
Your run_psalm.sh to convert the file paths used to work great, but suddenly doesn’t anymore – I’m assuming psalm changed it’s output somehow and I’m failing to adjust the regex to it. Any help?